import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.PriorityBlockingQueue;

import dbAdapter.DatabaseAdapter;

import CommonClass.*;
import WebSearch.*;
import CommonClass.URLlink;


public class Search_engine implements Runnable {

	private int num_found;
	private boolean finished; //finished searching status
	private String search_term;
	private int num_threads;
	public static final int max_num_thread=10;
	private PriorityBlockingQueue<Integer> running_threads;
	private PriorityBlockingQueue <Integer> available_threads;
	private Thread [] search_thread;
	private boolean running;
	private String search_result;
	private Thread main_thread;
	private String base_website;
	private static final int timeout= 30; //30s timeout
	private Timer timer;
	private Thread timer_thread;
	DatabaseAdapter databaseAdapter;

	static final int min_num_result=10;

	private TreeMap<String,IMG> image_results;



	public synchronized int get_num_result()
	{
		return image_results.size();
	}



	public synchronized void add_result(String img_url,IMG img)
	{
		image_results.put(img_url,img);
	}



	public synchronized TreeMap<String,IMG> get_image_result()
	{
		return image_results;
	}

	@Override
	public void run() {

		// TODO Auto-generated method stub
		//database.add_url(base_website);
		//System.out.println(base_website);
		try {



			while(get_num_result()<min_num_result)
			{				
				while(!databaseAdapter.getMutex())
				{
					Thread.sleep(1);
				}
				if(available_threads.size()>0&&databaseAdapter.getNumberOfUnprocessedURL()>0)
				{
					databaseAdapter.returnMutex();
					while(!databaseAdapter.getMutex())
					{
						Thread.sleep(1);
					}
					URLlink url = databaseAdapter.getUnprocessedURL();
					databaseAdapter.returnMutex();
					int id= available_threads.poll();
					System.out.println(url);
					running_threads.add(id);

					Search_thread_code search_thread_code = new Search_thread_code(id, this, url.getURL(), databaseAdapter,search_term);
					search_thread[id]= new Thread(search_thread_code);
					search_thread[id].start();

				}
				
				while(!databaseAdapter.getMutex())
				{
					Thread.sleep(1);
				}
				if(running_threads.size()==0&&databaseAdapter.getNumberOfUnprocessedURL()==0)
				{
					databaseAdapter.returnMutex();
					break;
				}
				databaseAdapter.returnMutex();

				Thread.sleep(1);
			}


		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			System.out.println("interrupted");


		} catch (Exception e) {
			// TODO Auto-generated catch block

			
			e.printStackTrace();
		}

		System.out.println("good");
		
		//wait all thread to stop
		for (int i=0; i<max_num_thread; i++) {
		
				if(search_thread[i]!=null&&search_thread[i].isAlive())
				{
					
					search_thread[i].interrupt();
				//	search_thread[i].stop();
					databaseAdapter.returnMutex();
					
					
					try {
						search_thread[i].join();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}


				}
	
		}	

		timer_thread.interrupt();
		databaseAdapter.clearSearch();
		update_result();


		running=false;
		finished=true;

	}


	private void update_result()
	{
		num_found=get_num_result();


		display_result();
	}


	private void display_result()
	{
		TreeMap<String, IMG> result= get_image_result();
		search_result="";
		for(Map.Entry<String,IMG> entry : result.entrySet()) {
			String template="<br><a href=\"$image_result\"><img src=\"$image_result\" ></a></br>";

			search_result+=template.replace("$image_result", entry.getKey());

		}
	}

	public synchronized void update_thread_finished(int id)
	{
		running_threads.remove(id);
		available_threads.add(id);
	}
	public Search_engine() {
		// TODO Auto-generated constructor stub
		num_found=0;
		finished=false;
		num_threads=0;
		running=false;
		search_term="";
		search_result="";
		databaseAdapter=DatabaseAdapter.getInstance();



	}




	private void restart()
	{
		num_found=0;
		finished=false;
		num_threads=0;
		running=false;
		search_result="";
		search_thread= new Thread[max_num_thread];
		running_threads= new PriorityBlockingQueue<Integer>();
		available_threads=new PriorityBlockingQueue<Integer>();

		for(int i=0; i<max_num_thread; i++)
		{
			available_threads.add(i);
			search_thread[i]= new Thread();
		}
		image_results=new TreeMap<String, IMG>();

	}

	public String get_search_result()
	{
		return search_result;
	}
	public String get_search_term()
	{
		return search_term;
	}
	public String get_website_search()
	{
		return base_website;
	}


	public boolean is_finished()
	{
		return finished;
	}



	public boolean set_search_term(String search_term, String base_website)
	{
		if(!this.search_term.equals(search_term)||!this.base_website.equals(base_website))
		{

			this.search_term=search_term;
			this.base_website=base_website;

			if(running)
			{
				main_thread.interrupt();
				timer_thread.interrupt();
				try {
					main_thread.join();
					timer_thread.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}


			restart();
			timer= new Timer(timeout,this);
			timer_thread=new Thread(timer);
			main_thread= new Thread(this);
			running=true;

			boolean validity =get_image_and_url_for_base_url();

			if(get_num_result()<10&&validity)
			{
				main_thread.start();
				timer_thread.start();
			}
			else
			{

				update_result();
				finished=true;
				running=false;
			}
			return validity;

		}
		else
		{
			return true;
		}




	}

	private boolean get_image_and_url_for_base_url()
	{
		WebSearchV3 ws2=new WebSearchV3();
		
		try {
			String[] searchterm_array = search_term.split(" ");
			URLlink url = new URLlink();
			url.setURL(base_website);
			databaseAdapter.setNewSearch(search_term, url);
			Vector<IMG> imgs1 =databaseAdapter.getIMGFromMatchingUrlAndKeyword(search_term.toLowerCase(),base_website );

			for(IMG img: imgs1)
			{
				image_results.put(img.getImageURLlink(), img);
			}
			if(get_num_result()<min_num_result)
			{
				dbAdapter.DatabaseAdapter db = ws2.fetchWebPageV1(ws2.formatDomain(base_website));


				ArrayList<IMG> listOfImg = ws2.getIMGs(searchterm_array, searchterm_array.length, db);
				for(IMG img: listOfImg)
				{
					image_results.put(img.getImageURLlink(), img);
				}		
				if(get_num_result() < min_num_result)
				{
					ws2.getHREFs(searchterm_array, searchterm_array.length, db);
				}
				db.returnMutex();

			}



			return true;

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			base_website="";
			return false;
		}

	}



	public boolean is_running()
	{
		return running;
	}
	public void stop()
	{
		main_thread.interrupt();
		try {
			main_thread.join();

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


}
